/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS  
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). 
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.  
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR  
 * COPYRIGHT LAW IS PROHIBITED.
 * 
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND  
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE  
 * MAY BE CONSIDERED TO BE A CONTRACT,
 * THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED 
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 * 
 */
package lineage.model.map;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.util.Collection;
import java.util.Map;
import java.util.StringTokenizer;

import lineage.database.tables.MapsTable;
import lineage.database.tables.bean.L1Maps;
import lineage.util.PerformanceTimer;
import lineage.util.StreamUtil;
import lineage.util.Util;
import lineage.util.collections.Maps;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 世界地图.
 * 
 * @version 2014年4月5日下午4:10:21
 * @author jrwz
 */
public final class L1WorldMap {
    private static final Logger LOG = LoggerFactory.getLogger(L1WorldMap.class);
    private Map<Integer, L1Map> list = Maps.newHashMap();
    /** 地图文件路径. */
    private static final String MAP_URL = "./maps/";

    /**
     * 静态初始化器，由JVM来保证线程安全.
     */
    private static class Holder {
        static L1WorldMap instance = new L1WorldMap();
    }

    /**
     * 取得该类的实例.
     */
    public static L1WorldMap getInstance() {
        return Holder.instance;
    }

    private L1WorldMap() {
        final PerformanceTimer timer = new PerformanceTimer();
        final StringBuilder sb = new StringBuilder();
        sb.append("加载TXT：地图");

        execute();
        if (list.isEmpty()) {
            LOG.error("地图资料生成数据载入异常");
            return;
        }

        sb.append("(");
        sb.append(list.size());
        sb.append(")\t耗时 ");
        sb.append(timer.elapsedTimeMillis());
        sb.append(" 毫秒");
        Util.message(Util.SYSTEM_MESSAGE, sb.toString());
    }

    /**
     * 全部地图资料生成.
     */
    private void execute() {
        final Map<Integer, L1Maps> mapDatas = MapsTable.getInstance().get();

        for (final Integer key : mapDatas.keySet()) {
            final L1Maps mapData = mapDatas.get(key);

            final int mapId = mapData.getMapId();
            final int xSize = mapData.getEndX() - mapData.getStartX() + 1;
            final int ySize = mapData.getEndY() - mapData.getStartY() + 1;
            L1V1Map map = null;
            try {
                map = new L1V1Map(mapId, this.read(mapId, xSize, ySize), mapData.getStartX(), mapData.getStartY());
            } catch (final Exception e) {
                LOG.error("地图资料生成数据载入异常：(" + mapId + ")", e);
            }
            if (map != null) {
                list.put(mapId, map);
            }
        }
    }

    /**
     * 指定地图加载障碍数据.
     * 
     * @param mapId
     *            - 地图编号
     * @param xSize
     *            - X坐标长度
     * @param ySize
     *            - Y坐标长度
     * 
     * @return 地图障碍数据数组
     */
    private byte[][] read(final int mapId, final int xSize, final int ySize) {
        final byte[][] map = new byte[xSize][ySize];
        LineNumberReader in = null;
        try {
            in = new LineNumberReader(new BufferedReader(new FileReader(MAP_URL + mapId + ".txt")));

            int y = 0;
            String line;
            while ((line = in.readLine()) != null) {
                if ((line.trim().length() == 0) || line.startsWith("#")) {
                    continue;
                }

                int x = 0;
                final StringTokenizer tok = new StringTokenizer(line, ",");
                while (tok.hasMoreTokens()) {
                    final byte tile = Byte.parseByte(tok.nextToken());
                    try {
                        map[x][y] = tile;
                    } catch (final ArrayIndexOutOfBoundsException e) {
                        // TXT档案内文字长度以及行数少于要求读取的长度
                        LOG.error("指定地图加载障碍数据异常：mapId(" + mapId + ") X(" + x + ") Y(" + y + ")", e);
                    }
                    x++;
                }
                y++;
            }
        } catch (final Exception e) {
            LOG.error("地图文件丢失：(" + mapId + ")");
        } finally {
            StreamUtil.close(in);
        }
        return map;
    }

    /**
     * 根据地图编号取得L1Map对象.
     * 
     * @param mapId
     *            - 地图编号
     * @return L1Map对象(如果没找到则返回L1NullMap)
     */
    public L1Map getMap(final int mapId) {
        L1Map map = list.get(mapId);
        if (map == null) {
            map = L1NullMap.getInstance();
        }
        return map;
    }

    /**
     * 取得缓存列表.
     * 
     * @return 列表中的所有元素
     */
    public Map<Integer, L1Map> get() {
        return list;
    }

    /**
     * 取得缓存列表.
     * 
     * @return 列表中的所有元素
     */
    public Collection<L1Map> getList() {
        return list.values();
    }
}
